﻿#include "libcomm.h"
#include "json/cJSON.h"

#define JSONMONITOR		((cJSON*)m_monitor)
#define JSONMONITORV(m)	((cJSON*)m)

JsonNode::~JsonNode() {}
JsonNode::JsonNode() : m_monitor(NULL){}

bool JsonNode::operator==(const JsonNode& rhs) const { return (this->m_monitor == rhs.m_monitor); }
bool JsonNode::operator!=(const JsonNode& rhs) const { return (this->m_monitor != rhs.m_monitor); }
JsonNode& JsonNode::operator=(const char* value) { return this->Set(value); }
JsonNode& JsonNode::operator=(bool value) { return this->Set(value); }
JsonNode& JsonNode::operator=(double value){ return this->Set(value);}
JsonNode& JsonNode::operator=(unsigned char value) { return this->Set(value); }
JsonNode& JsonNode::operator=(int value) { return this->Set(value); }
JsonNode& JsonNode::operator=(long long value) { return this->Set(value); }

JsonNode::operator String() const { return AsString(); }
JsonNode::operator bool() const { return AsBool(); }
JsonNode::operator double() const { return AsNumber(); }
JsonNode::operator unsigned char() const { return (unsigned char)AsNumber(); }
JsonNode::operator int() const { return (int)AsNumber(); }
JsonNode::operator long long() const { return (long long)AsNumber(); }

 JsonNode JsonNode::operator[](int index)
{
	 JsonNode node = Get(index);
	 if (!node.IsNull())
		 return node;
	 return AddObject();
}

JsonNode JsonNode::operator[](const char* name)
{
	JsonNode node = Get(name);
	if (!node.IsNull())
		return node;

	return AddObject(name);
}

JsonNode JsonNode::operator()(int index)
{
	JsonNode node = Get(index);
	if (!node.IsNull())
		return node;
	return AddArray();
}

JsonNode JsonNode::operator()(const char* name)
{
	JsonNode node = Get(name);
	if (!node.IsNull())
		return node;

	return AddArray(name);
}

bool JsonNode::IsNull() const
{
	return (NULL == m_monitor);
}


bool JsonNode::IsString() const
{
	return cJSON_IsString(JSONMONITOR) ? true : false;
}

bool JsonNode::IsBool() const
{
	return cJSON_IsBool(JSONMONITOR) ? true : false;
}

bool JsonNode::IsNumber() const
{
	return cJSON_IsNumber(JSONMONITOR) ? true : false;
}

bool JsonNode::IsArray() const
{
	return cJSON_IsArray(JSONMONITOR) ? true : false;
}

bool JsonNode::IsObject() const
{
	return cJSON_IsObject(JSONMONITOR) ? true : false;
}

String JsonNode::AsString() const
{
	if (IsObject())
		return ToJson(false);

	char* value = cJSON_GetStringValue(JSONMONITOR);
	if (NULL == value)
		return String::Empty;
	return value;
}

bool JsonNode::AsBool() const
{
	return cJSON_IsTrue(JSONMONITOR) ? true : false;
}

long double JsonNode::GetValue() const
{
	return cJSON_GetNumberValue(JSONMONITOR);
}

double JsonNode::AsNumber() const
{
	return (double)GetValue();
}

unsigned char JsonNode::AsByte() const
{
	return (unsigned char)GetValue();
}

int JsonNode::AsInt() const
{
	return (int)GetValue();
}

long long JsonNode::AsLong() const
{
	return (long long)GetValue();
}

void JsonNode::ResetValue()
{
	if (!IsNull())
	{
		// free value string.
		if (JSONMONITOR->valuestring != NULL)
		{
			cJSON_free(JSONMONITOR->valuestring);
			JSONMONITOR->valuestring = NULL;
		}

		// free array node.
		if (JSONMONITOR->child != NULL)
		{
			cJSON_Delete(JSONMONITOR->child);
			JSONMONITOR->child = NULL;
		}

		// set number to zero.
		cJSON_SetNumberHelper(JSONMONITOR, 0);
		//JSONMONITOR->type = cJSON_Object;

	}
}

const char* JsonNode::Name() const
{
	if (!IsNull())
	{
		return JSONMONITOR->string;
	}
	return NULL;
}

bool JsonNode::Has(const char* name) const
{
	return cJSON_HasObjectItem(JSONMONITOR, name) ? true : false;
}

JsonNode JsonNode::Get(const char* name) const
{
	JsonNode node;
	node.m_monitor = cJSON_GetObjectItem(JSONMONITOR, name);
	return node;
}

JsonNode JsonNode::Get(int index) const
{
	JsonNode node;
	//MYLIB_ASSERT(index >= 0 && index < this->Count());
	node.m_monitor = cJSON_GetArrayItem(JSONMONITOR, index);
	return node;
}

int JsonNode::Count() const
{
	return cJSON_GetArraySize(JSONMONITOR);
}

JsonNode& JsonNode::Remove(const char* name)
{
	cJSON_DeleteItemFromObject(JSONMONITOR, name);
	return *this;
}

JsonNode& JsonNode::Remove(int index)
{
	cJSON_DeleteItemFromArray(JSONMONITOR, index);
	return *this;
}

JsonNode& JsonNode::Set(const char* value_)
{
	do
	{
		String value = value_;
		if (value.null())
			value = String::Empty;

		if (IsNull())
			break;

		if (IsString())
		{
			cJSON_SetValuestring(JSONMONITOR, value);
			break;
		}

		// different type
		// replace with new type value.
		//
		ResetValue();
		JSONMONITOR->type = cJSON_String;
		JSONMONITOR->valuestring = (char*)cJSON_malloc(strlen(value) + 1);
		MYLIB_ASSERT_NOTNULL(JSONMONITOR->valuestring);
		strcpy(JSONMONITOR->valuestring, value);

	} while (false);

	return *this;
}

JsonNode& JsonNode::Set(bool value)
{
	do
	{
		if (IsNull())
			break;

		if (IsBool())
		{
			cJSON_SetBoolValue(JSONMONITOR, value);
			break;
		}

		// different type
		// replace self with new type node.
		//
		ResetValue();
		JSONMONITOR->type = value ? cJSON_True : cJSON_False;

	} while (false);

	return *this;
}

JsonNode& JsonNode::SetValue(long double value)
{
	do
	{
		if (IsNull())
			break;

		if (IsNumber())
		{
			cJSON_SetNumberValue(JSONMONITOR, value);
			break;
		}

		// different type
		// replace self with new type node.
		//
		ResetValue();
		JSONMONITOR->type = cJSON_Number;
		cJSON_SetNumberHelper(JSONMONITOR, value);

	} while (false);

	return *this;
}

JsonNode& JsonNode::Set(double value)
{
	return SetValue(value);
}

JsonNode& JsonNode::Set(unsigned char value)
{
	return SetValue(value);
}

JsonNode& JsonNode::Set(int value)
{
	return SetValue(value);
}

JsonNode& JsonNode::Set(long long value)
{
	return SetValue(value);
}

JsonNode& JsonNode::Add(const JsonNode& node)
{
	MYLIB_ASSERT(cJSON_AddItemToArray(JSONMONITOR, JSONMONITORV(node.m_monitor)));
	return *this;
}
JsonNode& JsonNode::Add(const char* value)
{
	if (!IsArray())
	{
		// change current node to array node.
		ResetValue();
		JSONMONITOR->type = cJSON_Array;
	}

	JsonNode node;
	node.m_monitor = cJSON_CreateString(value ? value : "");
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Add(node);
}
JsonNode& JsonNode::Add(bool value)
{
	if (!IsArray())
	{
		// change current node to array node.
		ResetValue();
		JSONMONITOR->type = cJSON_Array;
	}

	JsonNode node;
	node.m_monitor = cJSON_CreateBool(value);
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Add(node);
}
JsonNode& JsonNode::Add(double value)
{
	if (!IsArray())
	{
		// change current node to array node.
		ResetValue();
		JSONMONITOR->type = cJSON_Array;
	}

	JsonNode node;
	node.m_monitor = cJSON_CreateNumber(value);
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Add(node);
}
JsonNode& JsonNode::Add(unsigned char value)
{
	return Add((double)value);
}
JsonNode& JsonNode::Add(int value)
{
	return Add((double)value);
}
JsonNode& JsonNode::Add(long long value)
{
	return Add((double)value);
}

JsonNode& JsonNode::Insert(int index, const JsonNode& node)
{
	MYLIB_ASSERT(cJSON_InsertItemInArray(JSONMONITOR, index, JSONMONITORV(node.m_monitor)));
	return *this;
}

JsonNode& JsonNode::Insert(int index, const char* value)
{
	if (!IsArray())
	{
		// change current node to array node.
		ResetValue();
		JSONMONITOR->type = cJSON_Array;
	}

	JsonNode node;
	node.m_monitor = cJSON_CreateString(value ? value : "");
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Insert(index, node);
}

JsonNode& JsonNode::Insert(int index, bool value)
{
	if (!IsArray())
	{
		// change current node to array node.
		ResetValue();
		JSONMONITOR->type = cJSON_Array;
	}

	JsonNode node;
	node.m_monitor = cJSON_CreateBool(value);
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Insert(index, node);
}

JsonNode& JsonNode::Insert(int index, double value)
{
	if (!IsArray())
	{
		// change current node to array node.
		ResetValue();
		JSONMONITOR->type = cJSON_Array;
	}

	JsonNode node;
	node.m_monitor = cJSON_CreateNumber(value);
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Insert(index,node);
}

JsonNode& JsonNode::Insert(int index, unsigned char value)
{
	return Insert(index, (double)value);
}

JsonNode& JsonNode::Insert(int index, int value)
{
	return Insert(index, (double)value);
}

JsonNode& JsonNode::Insert(int index, long long value)
{
	return Insert(index, (double)value);
}

JsonNode& JsonNode::Add(const char* name, const JsonNode& node)
{
	MYLIB_ASSERT(cJSON_AddItemToObject(JSONMONITOR, name, JSONMONITORV(node.m_monitor)));
	return *this;
}
JsonNode& JsonNode::Add(const char* name, const char* value)
{
	JsonNode node;
	node.m_monitor = cJSON_CreateString(value ? value : "");
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Add(name, node);
}
JsonNode& JsonNode::Add(const char* name, bool value)
{
	JsonNode node;
	node.m_monitor = cJSON_CreateBool(value);
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Add(name, node);
}
JsonNode& JsonNode::Add(const char* name, double value)
{
	JsonNode node;
	node.m_monitor = cJSON_CreateNumber(value);
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return Add(name, node);
}
JsonNode& JsonNode::Add(const char* name, unsigned char value)
{
	return Add(name, (double)value);
}
JsonNode& JsonNode::Add(const char* name, int value)
{
	return Add(name, (double)value);
}
JsonNode& JsonNode::Add(const char* name, long long value)
{
	return Add(name, (double)value);
}

JsonNode JsonNode::AddArray(const char* name)
{
	JsonNode node = Get(name);
	if (!node.IsNull())
		return node;

	node.m_monitor = cJSON_AddArrayToObject(JSONMONITOR, name ? name : "");
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return node;
}

JsonNode JsonNode::AddObject(const char* name)
{
	JsonNode node;
	node.m_monitor = cJSON_AddObjectToObject(JSONMONITOR, name ? name : "");
	MYLIB_ASSERT_NOTNULL(node.m_monitor);
	return node;
}


String JsonNode::ToJson(bool format) const
{
	char* str = NULL;
	do
	{
		if (IsNull())
			break;

		if (format)
			str = cJSON_Print(JSONMONITOR);
		else
			str = cJSON_PrintUnformatted(JSONMONITOR);
		if (str == NULL)
		{
			LOGERR("failed to print json monitor.");
			break;
		}

	} while (false);

	if (NULL != str)
	{
		String sTmp = str;
		cJSON_free(str);
		return sTmp;
	}

	return String::Empty;
}

bool JsonNode::Save(const char* filename, bool format) const
{
	String str = ToJson(format);
	return File::SaveContent(filename, str.get(), str.length());
}

//////////////////////////////////////////////////////////////////////////

JsonRoot::JsonRoot()
{
	m_monitor = cJSON_CreateObject(); 
	MYLIB_ASSERT_NOTNULL(m_monitor);
}

JsonRoot::JsonRoot(const char* strorpath, bool ispath)
{
	String json;
	if (ispath)
		json = File::LoadContentText(strorpath);
	else
		json = strorpath;
	
	if (!json.empty())
	{
		cJSON* monitor = cJSON_Parse(json);
		if (monitor == NULL)
		{
			const char *error_ptr = cJSON_GetErrorPtr();
			if (error_ptr != NULL)
			{
				LOGERR("failed to parse json: %s.", error_ptr);
			}
		}

		m_monitor = monitor;
	}
}

JsonRoot::~JsonRoot() 
{
	if (NULL != m_monitor)
	{
		cJSON_Delete(JSONMONITOR);
		m_monitor = NULL;
	}
}